#ifndef _BLOCK_H_

#define _BLOCK_H_
#define BLOCK_SIZE 4096
#include <string>
#include <cstdlib>
#include <cassert>
#define INTSIZE 4
#define FLOATSIZE 4
#define DOUBLESIZE 8


typedef unsigned char byte;

class Block{
public:
	Block()
	{
		std::memset(block, 0, BLOCK_SIZE);
		this->dirtybit = 0;
	}

	void clear(int offset, int length)
	{
		for (int i = 0; i != length; ++i)
		{
			block[offset + i] = 0;
		}
	}
	byte readByte(int offset)const
	{
		assert(offset < BLOCK_SIZE);
		return block[offset];
	}
	void writeByte(int offset, byte b)
	{
		assert(offset < BLOCK_SIZE);
		block[offset] = b;
	}
	int readInt(int offset) const
	{
		return (int)readdata(offset, INTSIZE);
	}
	bool writeInt(int offset, int number)
	{
		writedata((void *)(&number), offset, INTSIZE);
		return true;
	}

	float readFloat(int offset) const
	{
		unsigned long long tmp = readdata(offset, FLOATSIZE);
		return *(reinterpret_cast<float *>(&tmp));
	}

	bool writeFloat(int offset, float number)
	{
		writedata((void *)(&number), offset, FLOATSIZE);
		return true;
	}

	double readDouble(int offset) const
	{
		unsigned long long tmp = readdata(offset, DOUBLESIZE);
		return *(reinterpret_cast<double *>(&tmp));
	}

	bool writeDouble(int offset, double number)
	{
		writedata((void *)(&number), offset, DOUBLESIZE);
		return true;
	}

	std::string readChar(int offset, int length)
	{
		std::string str = "";
		assert(offset + length < BLOCK_SIZE);
		byte *p = (byte *)(block + offset);
		for (int i = 0; i != length; ++i)
			str += p[i];
		return str;
	}
	//create a byte[length] in heap, and return a pointer
	byte *readBytes(int offset, int length)
	{
		byte *bytes = new byte[length];
		assert(offset + length < BLOCK_SIZE);
		byte *p = (byte *)(block + offset);
		for (int i = 0; i != length; ++i)
			bytes[i] = p[i];
		return bytes;
	}
	void writeBytes(byte *bytes, int offset, int length)
	{
		writedata(bytes, offset, length);
	}

	bool writeChar(std::string str, int offset)
	{
		assert(offset + str.size()< BLOCK_SIZE);
		byte *p = (byte *)(block + offset);
		for (int i = 0; i != str.size(); ++i)
			p[i] = str[i];
		return true;
	}

	std::string readVarchar(int offset)
	{
		std::string str = "";
		assert(offset< BLOCK_SIZE);
		byte *p = (byte *)(block + offset);
		int length = (int)readdata(offset, sizeof(byte));
		assert(offset + length < BLOCK_SIZE);
		for (int i = 0; i != length; ++i)
			str += p[i + 1];
		return str;
	}

	bool writeVarchar(std::string str, int offset)
	{
		assert(offset < BLOCK_SIZE);
		int length = str.size();
		assert(offset + length < BLOCK_SIZE);
		writedata((void *)(&length),  offset, sizeof(byte));
		byte *p = (byte *)(block + offset);
		for (int i = 0; i != length; ++i)
			p[i + 1] = str[i];
		return true;
	}

	Block(std::string filename, int offset)
	{
		std::memset(block, 0, BLOCK_SIZE);
		this->dirtybit = 0;
		this->filename = filename;
		this->offset = offset;
	}
	int offset;//block num
	byte block[BLOCK_SIZE];

private:
	bool dirtybit;
	friend class BufferManager;
	std::string filename;
	unsigned long long readdata(int offset, int length) const
	{
		unsigned long long ret = 0;
		assert(offset + length < BLOCK_SIZE);
		byte *p = (byte *)(block + offset);
		for (int i = length - 1; i >= 0; --i)
		{
			ret <<= sizeof(byte) * 8;
			ret |= ((unsigned long long)p[i] & 255);
		}
		return ret;
	}

	bool writedata(void *buf, int offset, int length)
	{
		unsigned long long ret = 0;
		assert(offset + length < BLOCK_SIZE);
		byte *p = (byte *)(block + offset);
		for (int i = 0; i != length; ++i)
		{
			p[i] = ((byte*)buf)[i];
		}
		return true;
	}
};

#endif